#pragma once

#include <vector>
#include <string>
#include <sstream>
#include <map>
#include <deque>
#include "JsonException.hpp"

namespace json {
	using namespace std;

	/**
	 * 定义Json的异常
	 */	
	DEF_EXCEPTION(JsonCastException);
	DEF_EXCEPTION(JsonItemException);

	
	/**
	 * Json对象的类型
	 */
	enum JsonType {
		JSON_TYPE_NULL, JSON_TYPE_BOOL,JSON_TYPE_DOUBLE, JSON_TYPE_INT, JSON_TYPE_OBJECT, JSON_TYPE_ARRAY, JSON_TYPE_STRING
	};


	/**
	 * Json对象的基类，仅仅表示Json对象的类型
	 */
	class JsonObject {
	protected:
		JsonObject(JsonType type) :
			_type(type) {
		}
	public:
		/**
		 *
		 */
		JsonType type() const {
			return _type;
		}
	private:
		JsonType _type;
	};
	

	/**
	 * Json的Null类型
	 */
	class JsonNull:public JsonObject{
	public:
		JsonNull():JsonObject(JSON_TYPE_NULL){}
	};


	/**
	 * Json的值类型
	 */
	template<class T>
	class JValue: public JsonObject {
	protected:
		JValue(JsonType t,T value):JsonObject(t),_value(value) {
		}
	public:
		inline T value() {
			return _value;
		}
		inline void value(T value) {
			_value = value;
		}
	protected:
		T _value;
	};
	/**
	 * Json的int值类型
	 */
	class JInt:public JValue<int>{
	public:
		JInt(int value):JValue<int>(JSON_TYPE_INT,value){
		}
	};
	/**
	 * Json的double值类型
	 */
	class JDouble:public JValue<double>{
	public:
		JDouble(double value):JValue<double>(JSON_TYPE_DOUBLE,value){
		}
	};
	/**
	 * Json的bool值类型
	 */
	class JBool:public JValue<bool>{
	public:
		JBool(bool value):JValue<bool>(JSON_TYPE_BOOL,value){
		}
	};
	/**
	 * Json的String值类型
	 */
	class JString:public JValue<String>{
	public:
		JString(String value):JValue<String>(JSON_TYPE_STRING,value){
		}
	};

	

	/**
	 * Json对象
	 */
	class JObject: public JsonObject {
	public:
		typedef map<String,JsonObject *>::iterator iterator;
	public:
		JObject() :
			JsonObject(JSON_TYPE_OBJECT) {
		}
	public:
		inline JsonObject* operator[](const String& key) {
			return items[key];
		}

		template<class T>
		T & get(const String& key){
			return json_cast<T>(items[key]);
		}

		inline void set(const String& key,JsonObject * value){
			items[key] = value;
		}

		/**
		 *
		 */
		inline void remove(const String& key){ items.erase(key);}
		/**
		 *
		 */
		inline iterator begin() { return items.begin(); }
		/**
		 *
		 */
		inline iterator end() { return items.end(); }
		/**
		 *
		 */
		inline size_t size() { return items.size(); }
	public:
		map<String, JsonObject *> items;
	};



	/**
	 * Json 数组
	 */
	class JArray: public JsonObject {
	public:
		typedef deque<JsonObject *>::iterator iterator;
	public:
		JArray() :
			JsonObject(JSON_TYPE_ARRAY) {
		}
	public:
		deque<JsonObject *>::value_type& operator[](size_t index) {
			return items[index];
		}
		/**
		 *
		 */
		inline void add(JsonObject &object) {
			items.push_back(&object);
		}

		inline void add(JsonObject *object) {
			items.push_back(object);
		}
		inline iterator begin(){return items.begin();}
		inline iterator end(){return items.end();}

		/**
		 *
		 */
		inline size_t size() {
			return items.size();
		}
	public:
		deque<JsonObject *> items;
	};
	// ------------------------------------------------------------------
	/**
	 *
	 */
	static JsonNull JNull;
	/**
	 *
	 */
	static JBool JTrue(true);
	/**
	 *
	 */
	static JBool JFalse(false);
	// ------------------------------------------------------------------	
	/**
	 * 是否是空值
	 */
	inline bool is_null(const JsonObject *object) {
		return object == NULL || object->type() == JSON_TYPE_NULL;
	}
	/**
	 * 是否是空值
	 */
	inline bool is_null(const JsonObject &object) {
		return object.type() == JSON_TYPE_NULL;
	}
	
	
	/**
	 * 对string进行编码
	 */
	String escape_string(const String& str);	
	
	// ------------------------------------------------------------------
	/* 将json数值对象转换成指定类型的值 */
	template <class T>
	inline T json_cast(JsonObject *){
		THROW_EXCEPTION(JsonCastException,L"unsupport type.");
	}	
	template<>
	inline int json_cast<int>(JsonObject *json){
		return static_cast<JInt *>(json)->value();
	}
	template<>
	inline double json_cast<double>(JsonObject *json){
		return static_cast<JDouble *>(json)->value();
	}
	template<>
	inline String json_cast<String>(JsonObject *json){
		return static_cast<JString *>(json)->value();
	}
	template<>
	inline bool json_cast<bool>(JsonObject *json){
		return static_cast<JBool *>(json)->value();
	}	
	
	// ------------------------------------------------------------------
	/* 将json对象的属性值转换成指定类型的值 */
	template <class T>
	inline T json_item(JsonObject *,const String &){
		THROW_EXCEPTION(JsonItemException,L"unsupport type.");
	}	
	template <>
	inline JsonObject *json_item<JsonObject *>(JsonObject *json,const String &key){
		return (*static_cast<JObject *>(json))[key];
	}
	
	template <>
	inline JObject *json_item<JObject *>(JsonObject *json,const String &key){
		return (JObject *)(*static_cast<JObject *>(json))[key];
	}
	template <>
	inline JArray *json_item<JArray *>(JsonObject *json,const String &key){
		return (JArray *)(*static_cast<JObject *>(json))[key];
	}
	template <>
	inline int json_item<int>(JsonObject *json,const String &key){
		return json_cast<int>((*static_cast<JObject *>(json))[key]);
	}	
	template <>
	inline double json_item<double>(JsonObject *json,const String &key){
		return json_cast<double>((*static_cast<JObject *>(json))[key]);
	}	
	template <>
	inline bool json_item<bool>(JsonObject *json,const String &key){
		return json_cast<bool>((*static_cast<JObject *>(json))[key]);
	}
	template <>
	inline String json_item<String>(JsonObject *json,const String &key){
		return json_cast<String>((*static_cast<JObject *>(json))[key]);
	}
	
	// ------------------------------------------------------------------
	/* 将json数组的属性值转换成指定类型的值 */
	template <class T>
	inline T json_item(JArray *jarray,size_t index){
		THROW_EXCEPTION(JsonItemException,L"unsupport type.");
	}	
	template <>
	inline JsonObject *json_item<JsonObject *>(JArray *jarray,size_t index){
		return (*jarray)[index];
	}
	template <>
	inline JObject *json_item<JObject *>(JArray *jarray,size_t index){
		return (JObject *)(*jarray)[index];
	}
	template <>
	inline JArray *json_item<JArray *>(JArray *jarray,size_t index){
		return (JArray *)(*jarray)[index];
	}
	template <>
	inline int json_item<int>(JArray *jarray,size_t index){
		return json_cast<int>((*jarray)[index]);
	}
	template <>
	inline double json_item<double>(JArray *jarray,size_t index){
		return json_cast<double>((*jarray)[index]);
	}
	template <>
	inline bool json_item<bool>(JArray *jarray,size_t index){
		return json_cast<bool>((*jarray)[index]);
	}
	template <>
	inline String json_item<String>(JArray *jarray,size_t index){
		return json_cast<String>((*jarray)[index]);
	}
	
	void print_json_object(JsonObject* object,int level = 0,const String& name = L"");
}	// end json